﻿Imports System.Collections.ObjectModel
Imports System.IO
Imports System.Threading
Imports System.ComponentModel
Imports FuncClasses

Public Class CSVImport
    Implements INotifyPropertyChanged

#Region "Threading"
    Private f As UnknownUnit
#End Region
#Region "Variables"
    Private _path As String
    Private _message As String
    Private _trennzeichen As String = ";"
    Private _wertkennzeichen As String = "'"
    Private xml As IDatabase
    Private _dispatcher As Windows.Threading.Dispatcher
    Private _usr As User
#End Region

    ''' <summary>
    ''' Creates a new instance of the Importer for Lexware-Data
    ''' </summary>
    ''' <param name="path">Path on your HDD to the exported settings.</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal path As String, ByRef _xml As IDatabase, Dispatcher As Windows.Threading.Dispatcher, usr As User)
        _path = path
        xml = _xml
        _usr = usr
        _dispatcher = Dispatcher

        ArticleDescription = "Bezeichnung"
        ArticleNumber = "Artikelnummer"
        ArticlePrice1 = "Preis 1"
        ArticlePrice2 = "Preis 2"
        ArticlePrice3 = "Preis 3"
        ArticleUnit = "Einheit"
        ArticleTax = "Steuersatz"
        ArticleWeight = "Gewicht"
        ArticleCategory = "Warengruppe"
        ArticleText = "Text"

        CustomerNumber = "Kundennummer"
        CustomerForname = "Vorname"
        CustomerSurname = "Nachname"
        CustomerSalutation = "Anrede"
        CustomerCompany = "Firma"
        CustomerAddition = "Zusatz"
        CustomerStreet = "Straße"
        CustomerZip = "Postleitzahl"
        CustomerCity = "Ort"
        CustomerPhone = "Telefon"
        CustomerMail = "EMAIL"

    End Sub

#Region "Import Articles"
    ''' <summary>
    ''' Event is raised when Task completed the file parsing. Thread safe
    ''' </summary>
    ''' <param name="items"></param>
    ''' <remarks></remarks>
    Public Event GetArticlesCompleted(ByVal items As ObservableCollection(Of Article))
    Public Event GetArticlesFailed()

    Public Property ArticleDescription As String
    Public Property ArticleNumber As String
    Public Property ArticlePrice1 As String
    Public Property ArticlePrice2 As String
    Public Property ArticlePrice3 As String
    Public Property ArticleUnit As String
    Public Property ArticleText As String
    Public Property ArticleTax As String
    Public Property ArticleWeight As String
    Public Property ArticleCategory As String

    Public Sub AsyncGetArticles()
        Dim t As Tasks.Task = Tasks.Task.Factory.StartNew(AddressOf FindArticles)
    End Sub

    Private Sub FindArticles()
        Dim sr As New StreamReader(_path, Text.Encoding.UTF8)

        Dim liste As New ObservableCollection(Of Article)
        Dim _kopf As String = sr.ReadLine()
        Dim _unbekannte As New ObservableCollection(Of Object())

        Dim _iArtBez, _iArtNr, _iArtPr1, _iArtPr2, _iArtPr3, _iArtEin, _iArtTxt, _iArtSteuer, _iArtGeproEin, _iArtKat As Integer

        Dim _kopfzeile As Collection(Of String) = AnalyzeLine(_kopf)
        _iArtBez = _kopfzeile.IndexOf(ArticleDescription)
        _iArtNr = _kopfzeile.IndexOf(ArticleNumber)
        _iArtPr1 = _kopfzeile.IndexOf(ArticlePrice1)
        _iArtPr2 = _kopfzeile.IndexOf(ArticlePrice2)
        _iArtPr3 = _kopfzeile.IndexOf(ArticlePrice3)
        _iArtEin = _kopfzeile.IndexOf(ArticleUnit)
        _iArtTxt = _kopfzeile.IndexOf(ArticleText)
        _iArtSteuer = _kopfzeile.IndexOf(ArticleTax)
        _iArtGeproEin = _kopfzeile.IndexOf(ArticleWeight)
        _iArtKat = _kopfzeile.IndexOf(ArticleCategory)

        If _iArtKat = -1 AndAlso _iArtPr1 = -1 AndAlso _iArtSteuer = -1 AndAlso _iArtTxt = -1 AndAlso _iArtEin = -1 Then
            _dispatcher.BeginInvoke(Sub()
                                        RaiseEvent GetArticlesFailed()
                                    End Sub)
        End If
        Do Until sr.Peek = -1
            Dim items As Collection(Of String) = AnalyzeLine(sr.ReadLine)
            Dim art As New Article()
            Try
                art.ArticleDescription = items(_iArtBez)
                art.ArticleID = items(_iArtNr)
                art.ArticlePrice1 = New EMoney(CDec(items(_iArtPr1)), True)
                Try
                    art.ArticlePrice1 = New EMoney(CDec(items(_iArtPr2)), True)
                    art.ArticlePrice1 = New EMoney(CDec(items(_iArtPr3)), True)
                Catch ex As Exception

                End Try
                If _iArtTxt <> -1 Then
                    art.ArticleText = items(_iArtTxt)
                End If

                art.TaxClass = TaxClass.GetByRate(items(_iArtSteuer), xml)
                Try : art.ArticleWeight = items(_iArtGeproEin) : Catch : End Try
                Try
                    art.ArticleUnit = Unit.GetByName(items(_iArtEin), xml)
                    liste.Add(art)
                Catch ex As Exception
                    For Each item As Object() In _unbekannte
                        If item(0) = items(_iArtEin) Then
                            art.ArticleUnit = item(1)
                            Exit Try
                        End If
                    Next
                    _dispatcher.BeginInvoke(Sub()
                                                Dim nachfragen As New UnknownUnit(items(_iArtEin), xml)
                                                If nachfragen.ShowDialog = True Then
                                                    _unbekannte.Add({items(_iArtEin), nachfragen.Unit})
                                                    art.ArticleUnit = nachfragen.Unit
                                                    liste.Add(art)
                                                Else : End If
                                            End Sub).Wait()
                    
                End Try
            Catch ex As Exception
                Console.WriteLine(sr.Peek())
            End Try
        Loop
        _dispatcher.BeginInvoke(Sub()
                                    RaiseEvent GetArticlesCompleted(liste)
                                End Sub)
    End Sub

    Private Function AnalyzeLine(ByVal line As String) As Collection(Of String)
        Dim rueckgabe As New Collection(Of String)
        Dim teile() As String = line.Split(Trennzeichen)

        For Each s As String In teile
            While s.Contains(Wertkennzeichen)
                s = s.Replace(Wertkennzeichen, "")
            End While
            rueckgabe.Add(s)
        Next
        Return rueckgabe
    End Function
#End Region

#Region "Import Kunden"
    ''' <summary>
    ''' Event is raised when Task completed the file parsing. Thread safe
    ''' </summary>
    ''' <param name="items"></param>
    ''' <remarks></remarks>
    Public Event GetCustomersCompleted(ByVal items As ObservableCollection(Of Customer))

    Public Property CustomerNumber As String
    Public Property CustomerForname As String
    Public Property CustomerSurname As String
    Public Property CustomerSalutation As String
    Public Property CustomerCompany As String
    Public Property CustomerAddition As String
    Public Property CustomerStreet As String
    Public Property CustomerZip As String
    Public Property CustomerCity As String
    Public Property CustomerPhone As String
    Public Property CustomerMail As String

    ''' <summary>
    ''' Returns a Collection of all Customers in the exported file
    ''' <remarks></remarks>
    ''' </summary>
    Public Sub GetCustomers()
        Dim t As Tasks.Task = Tasks.Task.Factory.StartNew(AddressOf FindCustomers)
    End Sub

    Private Sub FindCustomers()
        Dim sr As New StreamReader(_path, Text.Encoding.UTF8)
        Dim liste As New ObservableCollection(Of Customer)
        Dim _kopf As String = sr.ReadLine()

        Dim _kunNr, _kunVor, _kunNach, _kunAn, _kunFirm, _kunZus, _kunStr, _kunPLZ, _kunOrt, _kunTel, _kunFax, _kunEMail As Integer
        Dim _kopfzeile As Collection(Of String) = AnalyzeLine(_kopf)

        _kunNr = _kopfzeile.IndexOf(CustomerNumber)
        _kunVor = _kopfzeile.IndexOf(CustomerForname)
        _kunNach = _kopfzeile.IndexOf(CustomerSurname)
        _kunAn = _kopfzeile.IndexOf(CustomerSalutation)
        _kunFirm = _kopfzeile.IndexOf(CustomerCompany)
        _kunZus = _kopfzeile.IndexOf(CustomerAddition)
        _kunStr = _kopfzeile.IndexOf(CustomerStreet)
        _kunPLZ = _kopfzeile.IndexOf(CustomerZip)
        _kunOrt = _kopfzeile.IndexOf(CustomerCity)
        _kunTel = _kopfzeile.IndexOf(CustomerPhone)
        _kunEMail = _kopfzeile.IndexOf(CustomerMail)

        Do Until sr.Peek = -1
            Dim temp As String = sr.ReadLine
            Dim items As Collection(Of String) = AnalyzeLine(temp)
            Dim tcustomer As New Customer()
            tcustomer.Address.Salutation = items(_kunAn)
            tcustomer.SetKundenNummer(items(_kunNr))

            If items(_kunVor) = "" AndAlso String.IsNullOrEmpty(items(_kunFirm)) = False Then
                tcustomer.Address.Surname = items(_kunFirm)
            Else
                tcustomer.Address.Surname = items(_kunNach)
                tcustomer.Address.Forname = items(_kunVor)
                tcustomer.Address.Addition = items(_kunFirm)
            End If
            With tcustomer.Address
                .Addition += items(_kunZus)
                .ZipCode = items(_kunPLZ)
                .City = items(_kunOrt)
                Dim parsed As Address = ParseStreet(items(_kunStr))
                .Street = parsed.Street
                .No = parsed.No
            End With
            With tcustomer.Contact
                .Mail1 = items(_kunEMail)
                .Telefon1 = items(_kunTel)
                .Telefax1 = items(_kunFax)
            End With
            liste.Add(tcustomer)
        Loop
        _dispatcher.BeginInvoke(Sub()
                                    RaiseEvent GetCustomersCompleted(liste)
                                End Sub)
    End Sub

    Private Function ParseStreet(ByVal s As String) As Address
        Dim rueckgabe As New Address
        For i As Integer = 1 To s.Length
            If Char.IsDigit(Mid(s, i, 1)) Then
                rueckgabe.Street = Mid(s, 1, i - 2)
                rueckgabe.No = Mid(s, i)
                Exit For
            Else
                rueckgabe.Street = s
            End If
        Next
        Return rueckgabe
    End Function
#End Region

#Region "Import Auftrag"
    ''' <summary>
    ''' Event is raised when Task completed the file parsing. Thread safe
    ''' </summary>
    ''' <param name="items"></param>
    ''' <remarks></remarks>
    Public Event GetOrdersCompleted(ByVal items As ObservableCollection(Of Order))

    Public Sub GetAuftraege()
        Dim t As Tasks.Task = Tasks.Task.Factory.StartNew(AddressOf FindOrders)
    End Sub

    Private Sub FindOrders()
        Dim sr As New StreamReader(_path, Text.Encoding.UTF8)

        Dim liste As New ObservableCollection(Of Order)
        Dim _kopf As String = sr.ReadLine()

        Dim _aufDatum, _aufNr, _aufText, _aufBetrag As Integer
        Dim _kopfzeile As Collection(Of String) = AnalyzeLine(_kopf)

        _aufDatum = _kopfzeile.IndexOf("Belegdatum")
        _aufNr = _kopfzeile.IndexOf("Belegnummer")
        _aufText = _kopfzeile.IndexOf("Buchungstext")
        _aufBetrag = _kopfzeile.IndexOf("Buchungsbetrag")

        Dim kundenliste As ObservableCollection(Of Customer) = xml.GetAllCustomers(_usr)

        Dim letzterAuftrag As Integer = 0
        Dim zwischensumme As Decimal = 0.0
        Dim tauftrag As Order
        Do Until sr.Peek = -1
            Dim temp As String = sr.ReadLine
            Dim items As New Collection(Of String)
            items = AnalyzeLine(temp)
            If letzterAuftrag = items(_aufNr) Then
                zwischensumme += items(_aufBetrag)
            Else
                If tauftrag IsNot Nothing Then
                    tauftrag.OrderedArticles.Add(OrderedArticle.EmptyArticle(zwischensumme))
                    liste.Add(tauftrag)
                End If
                letzterAuftrag = items(_aufNr)
                tauftrag = New Order()
                tauftrag.Datum = New Datum(items(_aufDatum))
                tauftrag.DokumentArt = Dokumentart.Rechnung
                tauftrag.OrderID = (items(_aufNr))
                zwischensumme = 0
                zwischensumme = items(_aufBetrag)
                Dim kunde As String = items(_aufText)
                kunde = Mid(kunde, kunde.IndexOf(" ") + 2).Trim 'kunde.Replace("RG" + tauftrag.LaufendeNummer.ToString + " ", "")
                Dim teile() As String = kunde.Split(" ")
                For Each c As Customer In kundenliste
                    Dim treffer As Decimal = 0
                    For Each teilwort As String In teile
                        If c.Address.Surname.ToLower.Contains(teilwort.ToLower) OrElse c.Address.Forname.ToLower.Contains(teilwort.ToLower) OrElse c.Address.Addition.ToLower.Contains(teilwort.ToLower) Then
                            treffer += 1
                        End If
                    Next
                    If (treffer / teile.Count) >= 0.65 Then
                        tauftrag.Customer = c
                        Exit For
                    End If
                Next
            End If
        Loop
        tauftrag.OrderedArticles.Add(OrderedArticle.EmptyArticle(zwischensumme))
        liste.Add(tauftrag)
        _dispatcher.BeginInvoke(Sub()
                                    RaiseEvent GetOrdersCompleted(liste)
                                End Sub)
    End Sub
#End Region

    Public Property Message As String
        Get
            Return _message
        End Get
        Set(value As String)
            _message = value
            NotifyPropertyChanged("Message")
        End Set
    End Property

    Public Property FilePath As String
        Get
            Return _path
        End Get
        Set(value As String)
            _path = value
            NotifyPropertyChanged("FilePath")
        End Set
    End Property

    ''' <summary>
    ''' Default is ";"
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Trennzeichen As String
        Get
            Return _trennzeichen
        End Get
        Set(value As String)
            _trennzeichen = value
            NotifyPropertyChanged("Trennzeichen")
        End Set
    End Property

    ''' <summary>
    ''' Default is "'"
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Wertkennzeichen As String
        Get
            Return _wertkennzeichen
        End Get
        Set(value As String)
            _wertkennzeichen = value
            NotifyPropertyChanged("Wertkennzeichen")
        End Set
    End Property

    Protected Sub NotifyPropertyChanged(info As [String])
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
    End Sub

    Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class
